/**    
 * 文件名：AuthCodeService.java</br>
 *    
 * 版本信息：v1.0</br>
 * 日期：2017年9月11日</br>
 * © 2005-2017 雷技信息科技（上海）有限公司版权所有</br>
 *
 */
package com.logic.landseaserver.models.authcode.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.logic.common.domain.Code;
import com.logic.landseaserver.common.LandeaConstants;
import com.logic.landseaserver.common.LandeaConstants.AppropriateType;
import com.logic.landseaserver.common.LandeaConstants.CouponStatus;
import com.logic.landseaserver.common.LandeaConstants.QueryUesdCodeType;
import com.logic.landseaserver.common.LandseaErrorMessageEnum;
import com.logic.landseaserver.common.enums.BillTypeEnum;
import com.logic.landseaserver.common.enums.DepositEnum;
import com.logic.landseaserver.common.exception.LandseaException;
import com.logic.landseaserver.common.exception.ResultCodes.AuthorizationResultCode;
import com.logic.landseaserver.common.util.DateUtil;
import com.logic.landseaserver.domain.Coupon;
import com.logic.landseaserver.domain.CouponPutRecord;
import com.logic.landseaserver.domain.Project;
import com.logic.landseaserver.models.authcode.bean.QueryUsableAuthCodeReq;
import com.logic.landseaserver.models.authcode.bean.UseUpdateCoupon;
import com.logic.landseaserver.persistence.read.BillDetailReadMapper;
import com.logic.landseaserver.persistence.read.CoupUsedRecordReadMapper;
import com.logic.landseaserver.persistence.read.CouponPutRecordReadMapper;
import com.logic.landseaserver.persistence.read.CouponReadMapper;
import com.logic.landseaserver.persistence.read.PreOffrentDetailBillReadMapper;
import com.logic.landseaserver.persistence.read.ProjectReadMapper;
import com.logic.landseaserver.persistence.write.CoupUsedRecordWriteMapper;
import com.logic.landseaserver.persistence.write.CouponPutRecordWriteMapper;
import com.logic.landseaserver.persistence.write.CouponWriteMapper;
import com.logic.landseaserver.ws.dto.CouponDTO;
import com.logic.landseaserver.ws.dto.CouponGeneralDTO;
import com.logic.landseaserver.ws.dto.CouponPersonalDTO;
import com.logic.landseaserver.ws.dto.QueryCouponUesdDTO;
import com.logic.system.service.ICodeService;

/**
 *
 * 项目名称：system-server</br>
 * 类名称：AuthCodeService</br>
 * 类描述：授权码业务类</br>
 * 创建人：Aaron</br>
 * 创建时间：2017年9月11日 上午11:21:02</br>
 * 
 * @version 1.0
 *
 */
@Service
public class AuthCodeService
{
    private static final Logger LOGGER = LoggerFactory.getLogger(AuthCodeService.class);
    
    @Autowired
    private CouponReadMapper couponReadMapper;
    
    @Autowired
    private CouponWriteMapper couponWriteMapper;
    
    @Autowired
    private ICodeService codeService;
    
    @Autowired
    private ProjectReadMapper projectReadMapper;
    
    @Autowired
    private BillDetailReadMapper billDetailReadMapper;
    
    @Autowired
    private PreOffrentDetailBillReadMapper preOffrentDetailBillReadMapper;
    
    @Autowired
    private CoupUsedRecordWriteMapper coupUsedRecordWriteMapper;
    
    @Autowired
    private CoupUsedRecordReadMapper coupUsedRecordReadMapper;
    
    @Autowired
    private CouponPutRecordReadMapper couponPutRecordReadMapper;
    
    @Autowired
    private CouponPutRecordWriteMapper couponPutRecordWriteMapper;
    
    /**
     * 查询可使用的优惠码
     * 
     * @param queryUsableAuthCodeReq
     * @return
     * @throws LandseaException
     */
    public List<QueryCouponUesdDTO> queryUsableAuthCode(QueryUsableAuthCodeReq queryUsableAuthCodeReq)
        throws LandseaException
    {
        try
        {
            String prjAreaCode = checkQueryAutoCode(queryUsableAuthCodeReq);
            HashMap<String, Object> paramMap = new HashMap<String, Object>();
            // 授权费项
            List<String> authFees = new ArrayList<>();
            // 根据使用场景的不同 查询条件不同
            if (LandeaConstants.QueryUesdCodeType.CONTRACT.equals(queryUsableAuthCodeReq.getMainType()))
            {
                // 签约只有房租、押金、服务费、水费押金
                authFees.add(BillTypeEnum.CTBI8.getCode());
                authFees.add(BillTypeEnum.CTBI11.getCode());
                authFees.add(BillTypeEnum.CTBI9.getCode());
                authFees.add(BillTypeEnum.CTBI10.getCode());
                paramMap.put("feeType", LandeaConstants.FeeType.FEECREATED);
            }
            else if (LandeaConstants.QueryUesdCodeType.DEPOSIT.equals(queryUsableAuthCodeReq.getMainType()))
            {
                // 预定只有房租\定金
                authFees.add(BillTypeEnum.CTBI8.getCode());
                authFees.add(BillTypeEnum.CTBI18.getCode());
                paramMap.put("feeType", LandeaConstants.FeeType.FEECREATED);
            }
            else if (LandeaConstants.QueryUesdCodeType.MONTHBILL.equals(queryUsableAuthCodeReq.getMainType()))
            {
                // 查询当前月结账单有哪些费项
                List<String> billTypes = billDetailReadMapper.queryTypeByBillId(queryUsableAuthCodeReq.getBillId());
                if (billTypes != null)
                {
                    for (String type : billTypes)
                    {
                        authFees.add(type);
                    }
                }
                paramMap.put("offerType", LandeaConstants.OfferType.BYSINGLE);
                paramMap.put("feeType", LandeaConstants.FeeType.MONTHLYBILLCREATED);
            }
            else if (LandeaConstants.QueryUesdCodeType.OFFRENT.equals(queryUsableAuthCodeReq.getMainType()))
            {
                // 查询预结算单有哪些费项
                List<String> billTypes =
                    preOffrentDetailBillReadMapper.queryTypeByPreBillId(queryUsableAuthCodeReq.getBillId());
                if (billTypes != null)
                {
                    for (String type : billTypes)
                    {
                        authFees.add(type);
                    }
                }
                paramMap.put("offerType", LandeaConstants.OfferType.BYSINGLE);
                paramMap.put("codeType", LandeaConstants.CodeType.RELIEFTYPE);

            }
            if (authFees.size() > 0)
            {
                paramMap.put("authFees", authFees);
            }
            paramMap.put("userId", queryUsableAuthCodeReq.getUserId());
            paramMap.put("projectId", queryUsableAuthCodeReq.getProjectId());
            paramMap.put("areaCode", prjAreaCode);
            paramMap.put("roomId", queryUsableAuthCodeReq.getRoomId());
            // 查询个人/通用可使用的
            List<QueryCouponUesdDTO> personalCouponList = couponReadMapper.queryUesdCoupon(paramMap);
            return personalCouponList;
        }
        catch (Exception e)
        {
            LOGGER.error("queryUsableAuthCode|查询有效授权码数据异常.", e);
            throw LandseaException.createException(AuthorizationResultCode.E00550008, e);
        }
    }
    
    private String checkQueryAutoCode(QueryUsableAuthCodeReq queryUsableAuthCodeReq)
        throws LandseaException
    {
        if (StringUtils.isEmpty(queryUsableAuthCodeReq.getMainType()))
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.AUTHCODE_QUERY_MAINTYPE_ERROR);
        }
        if (queryUsableAuthCodeReq.getUserId() == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.AUTHCODE_QUERY_USERID_ERROR);
        }
        Boolean isContract = LandeaConstants.QueryUesdCodeType.CONTRACT.equals(queryUsableAuthCodeReq.getMainType());
        Boolean isDeposit = LandeaConstants.QueryUesdCodeType.DEPOSIT.equals(queryUsableAuthCodeReq.getMainType());
        Boolean isMonthly = LandeaConstants.QueryUesdCodeType.MONTHBILL.equals(queryUsableAuthCodeReq.getMainType());
        Boolean isOffrent = LandeaConstants.QueryUesdCodeType.OFFRENT.equals(queryUsableAuthCodeReq.getMainType());
        // 如果是月结|退房账单 账单编号不能为空
        if ((isMonthly || isOffrent) && queryUsableAuthCodeReq.getBillId() == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.AUTHCODE_QUERY_BILLID_ERROR);
        }
        // 如果是合同和预定 则项目编号不能为空
        if ((isContract || isDeposit) && queryUsableAuthCodeReq.getProjectId() == null)
        {
            throw LandseaException.createException(LandseaErrorMessageEnum.AUTHCODE_QUERY_PRJID_ERROR);
        }
       // if ((isContract || isDeposit))
        //{
            // 如果是预定和签约，则需根据项目编号查询出区域
            Project project = projectReadMapper.selectByPrimaryKey(queryUsableAuthCodeReq.getProjectId());
            if (project != null)
            {
                return project.getAreaCode();
            }else{
                return null;
            }
       // }
     //   return null;
    }
    
    /**
     * 
     * [简要描述]：过滤过期的，同时更新数据库</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-09-11)</br>
     *
     * @param couponList
     * @param isRemoveExpireCoupon 是否要从列表中移除过期的
     *
     */
    public void filterExpireCoupon(List<CouponDTO> couponList, boolean isRemoveExpireCoupon)
    {
        if (CollectionUtils.isEmpty(couponList))
        {
            return;
        }
        
        Iterator<CouponDTO> iterator = couponList.iterator();
        while (iterator.hasNext())
        {
            CouponDTO couponDTO = iterator.next();
            Date effectiveTime = couponDTO.getEffectiveEndTime();
            
            if (null == effectiveTime)
            {
                continue;
            }
            
            long currentTime = System.currentTimeMillis();
            if (currentTime >= effectiveTime.getTime())
            {
                try
                {
                    // 更新过期状态
                    Coupon upateCoupon = new Coupon();
                    // 已失效
                    upateCoupon.setStatus(CouponStatus.FAILURE);
                    upateCoupon.setId(couponDTO.getId());
                    couponWriteMapper.updateByPrimaryKeySelective(upateCoupon);
                }
                catch (Exception e)
                {
                    // 异常只是记录，无需影响正常业务流程
                    LOGGER.error("filterExpireCoupon|更新授权码过期状态失败.", e);
                }
                
                // 从列表中删除过期的授权码
                if (isRemoveExpireCoupon)
                {
                    iterator.remove();
                }
            }
        }
    }
    
    /**
     * 
     * [简要描述]：过滤过期的，同时更新数据库</br>
     * [详细描述]：个人的处理过期</br>
     * [作者]：Aaron(2017-09-11)</br>
     *
     * @param couponList
     * @param isRemoveExpireCoupon 是否要从列表中移除过期的
     *
     */
    public void filterPersonExpireCoupon(List<CouponPersonalDTO> couponList, boolean isRemoveExpireCoupon)
    {
        if (CollectionUtils.isEmpty(couponList))
        {
            return;
        }
        
        // 查询失效的中文描述
        String expireZhCodeDesc = CouponStatus.FAILURE;
        try
        {
            Code code = codeService.getCode(CouponStatus.FAILURE);
            expireZhCodeDesc = code.getCodeDescZh();
        }
        catch (Exception e)
        {
            // 异常只是记录，无需影响正常业务流程
            LOGGER.error("filterPersonExpireCoupon|查询systemCode失败.code=" + CouponStatus.FAILURE, e);
        }
        
        Iterator<CouponPersonalDTO> iterator = couponList.iterator();
        while (iterator.hasNext())
        {
            CouponPersonalDTO couponDTO = iterator.next();
            String effectiveTime = couponDTO.getEffectiveEndTime();
            
            if (null == effectiveTime)
            {
                continue;
            }
            
            Date effectiveDate = DateUtil.getInstence().convertDate(effectiveTime);
            
            long currentTime = System.currentTimeMillis();
            if (currentTime >= effectiveDate.getTime())
            {
                try
                {
                    // 更新过期状态
                    Coupon upateCoupon = new Coupon();
                    // 已失效
                    upateCoupon.setStatus(CouponStatus.FAILURE);
                    upateCoupon.setId(couponDTO.getId());
                    couponWriteMapper.updateByPrimaryKeySelective(upateCoupon);
                }
                catch (Exception e)
                {
                    // 异常只是记录，无需影响正常业务流程
                    LOGGER.error("filterExpireCoupon|更新授权码过期状态失败.", e);
                }
                
                couponDTO.setStatus(expireZhCodeDesc);
                couponDTO.setStatusCode(CouponStatus.FAILURE);
                
                // 从列表中删除过期的授权码
                if (isRemoveExpireCoupon)
                {
                    iterator.remove();
                }
            }
        }
    }
    
    /**
     * 
     * [简要描述]：过滤过期的，同时更新数据库</br>
     * [详细描述]：通用过期处理</br>
     * [作者]：Aaron(2017-09-11)</br>
     *
     * @param couponList
     * @param isRemoveExpireCoupon 是否要从列表中移除过期的
     *
     */
    public void filterGeneralExpireCoupon(List<CouponGeneralDTO> couponList, boolean isRemoveExpireCoupon)
    {
        if (CollectionUtils.isEmpty(couponList))
        {
            return;
        }
        
        // 查询失效的中文描述
        String expireZhCodeDesc = CouponStatus.FAILURE;
        try
        {
            Code code = codeService.getCode(CouponStatus.FAILURE);
            expireZhCodeDesc = code.getCodeDescZh();
        }
        catch (Exception e)
        {
            // 异常只是记录，无需影响正常业务流程
            LOGGER.error("filterGeneralExpireCoupon|查询systemCode失败.code=" + CouponStatus.FAILURE, e);
        }
        
        Iterator<CouponGeneralDTO> iterator = couponList.iterator();
        while (iterator.hasNext())
        {
            CouponGeneralDTO couponDTO = iterator.next();
            String effectiveTime = couponDTO.getEffectiveEndTime();
            
            if (null == effectiveTime)
            {
                continue;
            }
            
            Date effectiveDate = DateUtil.getInstence().convertDate(effectiveTime);
            long currentTime = System.currentTimeMillis();
            if (currentTime >= effectiveDate.getTime())
            {
                try
                {
                    // 更新过期状态
                    Coupon upateCoupon = new Coupon();
                    // 已失效
                    upateCoupon.setStatus(CouponStatus.FAILURE);
                    upateCoupon.setId(couponDTO.getId());
                    couponWriteMapper.updateByPrimaryKeySelective(upateCoupon);
                }
                catch (Exception e)
                {
                    // 异常只是记录，无需影响正常业务流程
                    LOGGER.error("filterExpireCoupon|更新授权码过期状态失败.", e);
                }
                
                couponDTO.setStatus(expireZhCodeDesc);
                couponDTO.setStatusCode(CouponStatus.FAILURE);
                
                // 从列表中删除过期的授权码
                if (isRemoveExpireCoupon)
                {
                    iterator.remove();
                }
            }
        }
    }
    
    /**
     * 
     * [简要描述]：付款后更新授权码为使用状态</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-10-20)</br>
     *
     * @param mainType 场景类型
     * @param mainId 主实体ID
     *
     */
    public void updateCouponStatusAfterPay(String mainType, Integer mainId)
    {
        LOGGER.info("updateCouponStatusAfterPay|更新授权码信息为已使用.mainType=" + mainType + ",mainId=" + mainId);
        
        // 说明mainType和mainId固定情况下，授权码ID不会重复
        Map<String, Object> queryMap = new HashMap<String, Object>();
        queryMap.put("uesdStatus", DepositEnum._DS2.getCode());
        queryMap.put("mainId", mainId);
        queryMap.put("mainType", mainType);
        // 查询出未使用的授权码
        List<UseUpdateCoupon> noneUseList = coupUsedRecordReadMapper.selectByMIdAndType(queryMap);
        if (CollectionUtils.isEmpty(noneUseList))
        {
            return;
        }
        
        // 更新使用表，使用状态为 已使用,只更新状态为未使用的,更新使用时间
        Date currentDate = new Date();
        Map<String, Object> updateMap = new HashMap<String, Object>();
        updateMap.put("lastModifiedDtm", currentDate);
        updateMap.put("lastModifiedBy", -1);
        updateMap.put("uesdStatus", DepositEnum._DS3.getCode());
        updateMap.put("noneUesdStatus", DepositEnum._DS2.getCode());
        updateMap.put("mainId", mainId);
        updateMap.put("mainType", mainType);
        coupUsedRecordWriteMapper.updateUseStatusByMIdAndType(updateMap);
        
        for (UseUpdateCoupon coupon : noneUseList)
        {
            Integer couponId = coupon.getId();
            Coupon updateCoupon = new Coupon();
            updateCoupon.setId(couponId);
            updateCoupon.updateCommonInfo(-1);
            updateCoupon.setCreatedBy(null);
            updateCoupon.setCreatedDtm(null);
            
            if (AppropriateType.PERSION.equals(coupon.getAppropriateType()))
            {
                // 个人授权码更新使用数量以及状态
                // 个人授权码数量就是1
                updateCoupon.setStatus(CouponStatus.USED);
                updateCoupon.setUsedAmount(1);
                LOGGER.info("updateCouponStatusAfterPay|更新个人授权码状态及数量,id=" + couponId);
                couponWriteMapper.updateByPrimaryKeySelective(updateCoupon);
            }
            else if (AppropriateType.COMMON.equals(coupon.getAppropriateType()))
            {
                // 通用授权码更新数量(状态不用更新)
                // 预定的房租优惠券支付时不更新数量
                if (!(QueryUesdCodeType.DEPOSIT.equals(mainType) &&  BillTypeEnum.CTBI8.getCode().equals(coupon.getAuthFee())))
                {
                    int useAmount = null == coupon.getUsedAmount() ? 0 : coupon.getUsedAmount().intValue();
                    useAmount += 1;
                    updateCoupon.setUsedAmount(useAmount);
                    couponWriteMapper.updateByPrimaryKeySelective(updateCoupon);
                    LOGGER.info("updateCouponStatusAfterPay|更新通用授权码数量,id=" + couponId);
                }
                
                // 更新投放批次使用数量
                // 先查询可更新的
                CouponPutRecord minCanUseRecord = couponPutRecordReadMapper.queryMinCanUseRecord(couponId);
                if (null ==  minCanUseRecord)
                {
                    LOGGER.info("updateCouponStatusAfterPay|更新通用授权码投放使用数量,查询不到可更新的记录.");
                }
                else
                {
                    if (!(QueryUesdCodeType.DEPOSIT.equals(mainType) &&  BillTypeEnum.CTBI8.getCode().equals(coupon.getAuthFee())))
                    {
                        CouponPutRecord updateCouponPutRecord = new CouponPutRecord();
                        updateCouponPutRecord.setId(minCanUseRecord.getId());
                        updateCouponPutRecord.updateCommonInfo(-1);
                        updateCouponPutRecord.setCreatedBy(null);
                        updateCouponPutRecord.setCreatedDtm(null);
                        
                        Integer putUsedAmount = minCanUseRecord.getUsedAmount();
                        putUsedAmount = null == putUsedAmount ? 0 : putUsedAmount.intValue();
                        putUsedAmount += 1;
                        updateCouponPutRecord.setUsedAmount(putUsedAmount);
                        couponPutRecordWriteMapper.updateByPrimaryKeySelective(updateCouponPutRecord);
                        LOGGER.info("updateCouponStatusAfterPay|更新通用授权码投放使用数量,id=" + couponId);
                    }
                }
            }
        }
    }
}
